/**
 * 
 */
package algoritmos;

import java.io.BufferedReader;
import java.io.IOException;
import java.util.StringTokenizer;
import java.util.Vector;

import Jama.Matrix;

import matrices.centro.Clase;
import problema.FormaProblema;
import problema.Utilidades;

/**
 * @author Jose Antonio Gonzalez, Ambrin Chaudhary
 * 
 */
public class Lloyd implements FormaProblema {

	public Vector<Matrix> vectorMuestras;
	public Vector<Clase> vectorCentros;
	public Vector<Clase> vectorCentConverg;
	public double alfa = 0.1;
	public double epsilon = 0.1;
	public int kmax = 5;
	public boolean continuar = true;
	public int lonVect = 0;

   /* public Lloyd()
    {
    	this.vectorMuestras = new Vector<Matrix>();
        this.vectorCentros = new Vector<Clase>();
    }*/
    
    
	private Matrix actualiza(Matrix x, Matrix c) {
		Matrix m1 = x.minus(c);
	
		Matrix m2 = m1.times(alfa);
		Matrix m3 = m2.plus(c);
		return m3;
		//return x.minus(c).times(alfa).plus(c);

	}

	private void ClonarVectConverg() {
		this.vectorCentConverg = new Vector<Clase>();
		for (int i = 0; i < this.vectorCentros.size(); i++) {
			Clase c1 = new Clase();
			Matrix c2 = this.vectorCentros.get(i).getCentro();

			c1.setCentro(Matrix.constructWithCopy(c2.getArray()));
			this.vectorCentConverg.add(c1);
		}
	}

	private void elvaluarCentros() {

		ClonarVectConverg();

		for(int i = 0; i < this.vectorCentros.size(); i++)
		{
			this.vectorCentros.get(i).deleteAllElemetns();
		}
		
		
		for (int i = 0; i < this.vectorMuestras.size(); i++) {

			Matrix xi = this.vectorMuestras.get(i);
			double min = Double.MAX_VALUE;
			int centro = -1;

			for (int j = 0; j < vectorCentros.size(); j++) {
				double dist = Utilidades.dist(vectorCentros.get(j).getCentro(),
						xi);
				double aux = Math.min(min, dist);
				if (aux == dist) {
					min = dist;
					centro = j;
				}
			}
			Clase centr = vectorCentros.get(centro);
			Matrix c = centr.getCentro();
			c = this.actualiza(xi, c);
			centr.setCentro(c);
			centr.addElement(xi);

		}

		for (int j = 0; j < vectorCentros.size(); j++) {
			Matrix c1 = this.vectorCentConverg.get(j).getCentro();
			Matrix c2 = this.vectorCentros.get(j).getCentro();

			if (Utilidades.dist(c1, c2) < this.epsilon) {
				this.continuar = false;
			} else
				this.continuar = true;
		}

	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see problema.FormaProblema#ciclo(java.util.Vector)
	 */
	public Clase ciclo(Vector<Double> m) {
		Matrix matriz = Utilidades.toMatrix(m);

		Matrix mdimen = this.vectorCentros.get(0).getCentro();
		if((matriz.getColumnDimension() != mdimen.getColumnDimension()) ||
				matriz.getRowDimension() != mdimen.getRowDimension())
			System.err.println("Hay elementos de enos en los vectores");
		
		double min = Double.MAX_VALUE;
		int centro = -1;

		for (int j = 0; j < vectorCentros.size(); j++) {
			double dist = Utilidades.dist(vectorCentros.get(j).getCentro(),
					matriz);
			double aux = Math.min(min, dist);
			if (aux == dist) {
				min = dist;
				centro = j;
			}
		}
		Clase centr = vectorCentros.get(centro);
		Matrix c = centr.getCentro();
		Matrix aux = this.actualiza(matriz, c);
		c = aux;
		centr.setCentro(c);
		centr.addElement(matriz);

		return centr;

	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see problema.FormaProblema#entrenar(java.util.Vector)
	 */
	public void entrenar(Vector<Double> listaParametros) {
		this.alfa = listaParametros.get(0);
		this.epsilon = listaParametros.get(6);
		this.kmax = (int) ((double) listaParametros.get(3));

		for (int i = 0; i < kmax; i++) {
			if (continuar)
				elvaluarCentros();
		}

		/*
		 * for (int i = 0; i< this.vectorMuestras.size(); i++) {
		 * 
		 * Matrix xi = this.vectorMuestras.get(i); double min =
		 * Double.MAX_VALUE; int centro = -1;
		 * 
		 * for(int j = 0; j< vectorCentros.size(); j++) { double dist =
		 * Utilidades.dist(vectorCentros.get(j).getCentro() , xi); double aux =
		 * Math.min(min, dist); if(aux == dist) { min = dist; centro = j; } }
		 * 
		 * Matrix c = vectorCentros.get(centro).getCentro(); c =
		 * this.actualiza(xi, c);
		 * 
		 *  }
		 * 
		 */

	}

	public void cargarClases(Vector<Clase> inClass, Vector<Matrix> inMuestras) {

		this.vectorCentros = inClass;
		this.vectorMuestras = inMuestras;
		
		if(this.vectorMuestras.size() > 0)
        	this.lonVect = this.vectorMuestras.get(0).getColumnDimension();
        else
        	this.lonVect = 0;
	}

	public void cargarFichero(BufferedReader inStream) throws IOException {

		this.vectorCentros = new Vector<Clase>();
		this.vectorMuestras = new Vector<Matrix>();

		Clase clase = null;
		boolean leerCentro = false;

		try {

			// BufferedReader entrada = new BufferedReader(new
			// FileReader(fichero));

			boolean primeralinea = true;
			String s = "";
			do {
				s = inStream.readLine();
				if (s == null)
					break;
				else {
					if (leerCentro) {
						StringTokenizer st = new StringTokenizer(s, ",");

						if(primeralinea)
						{
							this.lonVect = st.countTokens();
							primeralinea = false;
						}
						
						
						int i = 0;
						int cant = st.countTokens();
						double d[][] = new double[1][cant];
						while (st.hasMoreTokens()) {

							String s1 = st.nextToken();
							double aux = Double.parseDouble(s1);
							d[0][i] = aux;
							i++;
						}
						clase.setCentro(new Matrix(d));
						this.vectorCentros.add(clase);
						leerCentro = false;
					}

					else if (s.contains("centro:")) 
					{
						clase = new Clase();
						leerCentro = true;
					
					} 
					else 
					{
						
						
						StringTokenizer st = new StringTokenizer(s, ",");


						
						if(primeralinea)
						{
							this.lonVect = st.countTokens();
							primeralinea = false;
						}
						
						
						int i = 0;
						int cant = st.countTokens();
						double d[][] = new double[1][cant];
						while (st.hasMoreTokens()) {

							String s1 = st.nextToken();
							double aux = Double.parseDouble(s1);
							d[0][i] = aux;
							i++;
						}
						Matrix m = new Matrix(d);
						if (clase != null)
							clase.addElement(m);

						this.vectorMuestras.add(m);
						
					}
				}
			} while (true);

		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			System.out.println("Error al cargar archivo");
			throw e;
		}

	}

	public String toStringCentros() {
		String s = "";
		Clase c = null;
		for (int i = 0; i < this.vectorCentros.size(); i++) {
			s += this.vectorCentros.get(i).toString() + "\n";
			// Utilidades.matrixToString(c.getCentro()) + "\n";
		}

		return s;
	}

	public String toStringMatrices() {
		String s = "";
		Matrix m = null;
		for (int i = 0; i < this.vectorMuestras.size(); i++) {
			m = this.vectorMuestras.get(i);
			s += Utilidades.matrixToString(m) + "\n";
		}

		return s;
	}

        public Vector<Clase> getClases() {

		return this.vectorCentros;
	}

        
		public int longVect() {
		
			return this.lonVect;
		}

}
